#include "Renderer.h"


/*-----------------------------------------------------------------------------------------------*/
Renderer::Renderer()
{

}
/*-----------------------------------------------------------------------------------------------*/
bool Renderer::init(HWND hwnd)
{
   m_dxObject = Direct3DCreate9(D3D_SDK_VERSION);

   if(!m_dxObject)
   {
      std::cout << "Failed to create dxObject" << std::endl;
      return false;
   }

   D3DDISPLAYMODE displayMode;

   HRESULT result = m_dxObject->GetAdapterDisplayMode(D3DADAPTER_DEFAULT, &displayMode);

   if(result != D3D_OK)
   {
      std::cout << "Failed on GetAdapterDisplayMode" << std::endl;
      return false;
   }

   D3DPRESENT_PARAMETERS PresentParams;
   memset(&PresentParams, 0, sizeof(D3DPRESENT_PARAMETERS));

   PresentParams.Windowed = TRUE;
   PresentParams.SwapEffect = D3DSWAPEFFECT_DISCARD;
   PresentParams.EnableAutoDepthStencil = TRUE;
   PresentParams.AutoDepthStencilFormat = D3DFMT_D16;

   PresentParams.BackBufferFormat = displayMode.Format;
   PresentParams.BackBufferCount = 1;
   PresentParams.hDeviceWindow = 0;
   PresentParams.Flags = 0;
   PresentParams.FullScreen_RefreshRateInHz = D3DPRESENT_RATE_DEFAULT;
   PresentParams.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE;
   
   result = m_dxObject->CreateDevice(
      D3DADAPTER_DEFAULT,
      D3DDEVTYPE_HAL,
      hwnd,
      D3DCREATE_SOFTWARE_VERTEXPROCESSING,
      &PresentParams,
      &m_dxDevice
      );

   if(result != D3D_OK)
   {
      std::cout << "Failed to create dxDevice" << std::endl;
      return false;
   }

   if ( !m_vertexBuffer.create(m_dxDevice) )
   {
      std::cout << "Failed to create VertexBuffer" << std::endl;
      return false;
   }

   if ( !m_textureVertexBuffer.create(m_dxDevice) )
   {
      std::cout << "Failed to create textureVertexBuffer" << std::endl;
      return false;
   }


   //////////////////////////////////////////////////////////////////////////
   //Camera
   D3DXMATRIX dxMatrix;
   D3DXVECTOR3 dxEyePosition(0.0f, 0.0f, -5.0f);
   D3DXVECTOR3 dxLookPosition(0.0f, 0.0f, 0.0f);
   D3DXVECTOR3 dxUpVertex(0.0f, 1.0f, 0.0f);
   D3DXMatrixIdentity(&dxMatrix);
   D3DXMatrixLookAtLH(&dxMatrix, &dxEyePosition, &dxLookPosition, &dxUpVertex);
   result = m_dxDevice->SetTransform(D3DTS_VIEW, &dxMatrix);
   if ( result != D3D_OK )
   {
       std::cout << "Failed to set LookAt position" << std::endl;
       return false;
   }

   D3DXMATRIX mat;
   D3DVIEWPORT9 viewPort;
   m_dxDevice->GetViewport(&viewPort);
   D3DXMatrixOrthoLH(&mat, viewPort.Width, viewPort.Height, 0.1f, 50.0f);
   result = m_dxDevice->SetTransform(D3DTS_PROJECTION, &mat);
   if ( result != D3D_OK )
   {
      std::cout << "Failed to set ViewPort position" << std::endl;
      return false;
   }
   
   //////////////////////////////////////////////////////////////////////////
   //Render States
   m_dxDevice->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE);
   m_dxDevice->SetRenderState(D3DRS_LIGHTING, FALSE);
   //m_dxDevice->SetRenderState(D3DRS_NORMALIZENORMALS, TRUE);
   //m_dxDevice->SetRenderState(D3DRS_AMBIENT,0xffffff);
   //m_dxDevice->SetRenderState(D3DRS_ZWRITEENABLE, FALSE);
   m_dxDevice->SetRenderState(D3DRS_FILLMODE, D3DFILL_SOLID);
   m_dxDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE);
   //m_dxDevice->SetRenderState(D3DRS_BLENDOP, D3DBLENDOP_ADD);
   //m_dxDevice->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA);
   m_dxDevice->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA);
   //m_dxDevice->SetRenderState(D3DRS_SPECULARENABLE, FALSE);
   //m_dxDevice->SetRenderState(D3DRS_STENCILENABLE, FALSE);
   m_dxDevice->SetRenderState(D3DRS_ZENABLE, FALSE); // para 3D
   //m_dxDevice->SetRenderState(D3DRS_ZFUNC, D3DCMP_LESS);
   //////////////////////////////////////////////////////////////////////////

   return true;
}
/*-----------------------------------------------------------------------------------------------*/
void Renderer::clear(short red, short green, short blue)
{
   m_dxDevice->Clear(0,NULL,D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER,D3DCOLOR_XRGB(red, green, blue),1.0f,0);
}
/*-----------------------------------------------------------------------------------------------*/
void Renderer::beginFrame()
{
   this->clear(0,0,0);

   m_dxDevice->BeginScene();
}
/*-----------------------------------------------------------------------------------------------*/
void Renderer::endFrame()
{
   m_dxDevice->EndScene();
}
/*-----------------------------------------------------------------------------------------------*/
void Renderer::present(HWND hwnd)
{
   m_dxDevice->Present(NULL, NULL, NULL, NULL);
}
/*-----------------------------------------------------------------------------------------------*/
void Renderer::deInit()
{
   m_dxDevice->Release();
   m_dxObject->Release();
}
/*-----------------------------------------------------------------------------------------------*/
bool Renderer::DrawElements(USHORT vertexCount, ColorVertex* vertices, USHORT primCount, PRIM_TYPE primType)
{
   m_vertexBuffer.bind();
   
   return ( m_vertexBuffer.draw(vertices, vertexCount, primCount, primType) );
}
/*-----------------------------------------------------------------------------------------------*/
bool Renderer::DrawElements(USHORT vertexCount, TextureVertex* vertices, USHORT primCount, PRIM_TYPE primType)
{
   m_textureVertexBuffer.bind();

   return ( m_textureVertexBuffer.draw(vertices, vertexCount, primCount, primType) );
}
/*-----------------------------------------------------------------------------------------------*/
void Renderer::setMatrixMode(MatrixMode mMode)
{
   m_currentMatrixMode = static_cast<D3DTRANSFORMSTATETYPE>(mMode);
}
/*-----------------------------------------------------------------------------------------------*/
void Renderer::loadIdentity()
{
   D3DXMATRIX dxMatrix;

   D3DXMatrixIdentity(&dxMatrix);

   if (m_currentMatrixMode == VIEW)
   {
      D3DXVECTOR3 dxEyePosition(0.0f, 0.0f, 0.0f);
      D3DXVECTOR3 dxLookPosition(0.0f, 0.0f, 0.0f);
      D3DXVECTOR3 dxUpVertex(0.0f, 1.0f, 0.0f);

      D3DXMatrixLookAtLH(&dxMatrix, &dxEyePosition, &dxLookPosition, &dxUpVertex);
   }

   m_dxDevice->SetTransform(m_currentMatrixMode, &dxMatrix);
}
/*-----------------------------------------------------------------------------------------------*/
void Renderer::Translate(Vector3 translation)
{
   D3DXMATRIX dxMatrix;	

   D3DXMatrixTranslation(&dxMatrix, translation.x,  translation.y, translation.z);

   m_dxDevice->MultiplyTransform(m_currentMatrixMode, &dxMatrix);
}
/*-----------------------------------------------------------------------------------------------*/
void Renderer::RotateX(float angle)
{
   D3DXMATRIX dxMatrix;
   D3DXMatrixRotationX(&dxMatrix, angle);

   m_dxDevice->MultiplyTransform(m_currentMatrixMode, &dxMatrix);
}
/*-----------------------------------------------------------------------------------------------*/
void Renderer::RotateY(float angle)
{
   D3DXMATRIX dxMatrix;
   D3DXMatrixRotationY(&dxMatrix, angle);

   m_dxDevice->MultiplyTransform(m_currentMatrixMode, &dxMatrix);
}
/*-----------------------------------------------------------------------------------------------*/
void Renderer::RotateZ(float angle)
{
   D3DXMATRIX dxMatrix;
   D3DXMatrixRotationZ(&dxMatrix, angle);

   m_dxDevice->MultiplyTransform(m_currentMatrixMode, &dxMatrix);
}
/*-----------------------------------------------------------------------------------------------*/
void Renderer::Scale(Vector3 scale)
{
   D3DXMATRIX dxMatrix;

   D3DXMatrixScaling(&dxMatrix, scale.x,  scale.y, scale.z);

   m_dxDevice->MultiplyTransform(m_currentMatrixMode, &dxMatrix);
}

/*-----------------------------------------------------------------------------------------------*/
bool Renderer::bindTexture(Texture::TexturePtr texture)
{
   IDirect3DTexture9* pD3DTexture = m_D3DTextureMap[texture->getFileName()];

   return ( m_dxDevice->SetTexture(0, pD3DTexture ) == D3D_OK );
}
/*-----------------------------------------------------------------------------------------------*/
void Renderer::unbindTexture()
{
    m_dxDevice->SetTexture(0, NULL);
}
/*-----------------------------------------------------------------------------------------------*/
bool Renderer::loadTexture(const char* filename, Texture::TexturePtr texture)
{
   
   D3DXIMAGE_INFO imageInfo;
   LPDIRECT3DTEXTURE9 tex;

   ColorKey colorKey;
   colorKey = texture.get()->getColorKey();
   D3DXCOLOR D3DColorKey = D3DCOLOR_XRGB(colorKey.red, colorKey.green, colorKey.blue);

   HRESULT hr = D3DXCreateTextureFromFileEx(m_dxDevice,
      texture->getFileName().c_str(), 
      0,
      0,
      0,
      0,
      D3DFMT_UNKNOWN,
      D3DPOOL_MANAGED,
      D3DX_FILTER_NONE,
      D3DX_FILTER_NONE,
      D3DColorKey,
      &imageInfo,
      NULL,
      &tex);

   if (hr != D3D_OK)
      return false;

   texture->setWidth(imageInfo.Width);
   texture->setHeight(imageInfo.Height);

   m_D3DTextureMap[texture->getFileName()] = tex;

   return true;
}
//----------------------------------------------------------------